package obecto.task.progress
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.ProgressEvent;
	
	import obecto.core.FLGlobals;

	[Event(name="complete", type="flash.events.Event")]

	public class ProgressBarController extends EventDispatcher
	{
		[Bindable]
		public var minPercentsPerFrame : Number = 0.01;
		[Bindable]
		public var maxPercentsPerFrame : Number = 2;
		[Bindable]
		public var normalPercentsPerFrame : Number = 0.6;				
		[Bindable]
		public var sensitivePercentsDifference : Number = 25;
		[Bindable]
		public var useFakeSmothness : Boolean = false;
		[Bindable]
		public var progressedProperty : String = "width";
		[Bindable]
		public var progressedPropertyMaxValue : Number = 100;
		[Bindable]
		public var progressedPropertyMinValue : Number = 0;
		[Bindable]
		public var changeCompletionTime : Number = 0.2;
		
		private var _bar : Object;
		public function get bar() : Object
		{
			return _bar;
		}
		public function set bar(value : Object) : void
		{
			_bar = value;
		}
		
		private var _progressPercents : Number = 0;
		public function get progressPercents() : Number
		{
			return _progressPercents;
		}
		
		private var _progressDispatcher : IEventDispatcher;
		[Bindable]
		public function set progressDispatcher(value : IEventDispatcher) : void
		{
			if (_progressDispatcher)
			{
				_progressDispatcher.removeEventListener(ProgressEvent.PROGRESS, handleProgressDispatcherProgress);	
			}
			_progressDispatcher = value;
			if (_progressDispatcher)
			{
				_progressDispatcher.addEventListener(ProgressEvent.PROGRESS, handleProgressDispatcherProgress);
			}
		}
		public function get progressDispatcher() : IEventDispatcher
		{
			return _progressDispatcher;
		}
		
		private var _fakeProgressPercents : Number = 0;
		private var _currentPercentsPerFrame : Number;
		
		public function ProgressBarController()
		{
			super();
		}
		
		public function progressBy(percents : Number) : void
		{
			progressTo(_progressPercents + percents);
		}
	
		public function progressFull() : void
		{
			_fakeProgressPercents = 100;
			progressTo(100);
		}
	
		public function reset() : void
		{
			_fakeProgressPercents = 0;
			_progressPercents = 0;
			
			_bar[progressedProperty] = progressedPropertyMinValue; 
		}
		
		private var isEnterFrameHandlerActive : Boolean = false;
		public function progressTo(percents : Number) : void
		{
			if(!isEnterFrameHandlerActive)
			{
				isEnterFrameHandlerActive = true;
				FLGlobals.topLevelSprite.addEventListener(Event.ENTER_FRAME, handleEnterFrame);
			}
			
			if(percents < 0)
			{
				percents = 0;
			}		
			
			if(percents > 100)
			{
				percents = 100;
			}		
			
			_progressPercents = percents;
		}
		
		public function forceProgressTo(percents : Number) : void
		{
			_progressPercents = percents;
			_fakeProgressPercents = percents;
			onProgressUpdated();
		}
		
		
		private function onProgressUpdated() : void
		{
			if(_fakeProgressPercents < 0)
			{
				_fakeProgressPercents = 0;
			}		
			
			if(_fakeProgressPercents > 100)
			{
				_fakeProgressPercents = 100;
			}
			
			_bar[progressedProperty] = (_fakeProgressPercents / 100) * progressedPropertyMaxValue;
			
			if(_fakeProgressPercents >= 100)
			{
				FLGlobals.topLevelSprite.removeEventListener(Event.ENTER_FRAME, handleEnterFrame);
				isEnterFrameHandlerActive = false;
				
				dispatchEvent(new Event(Event.COMPLETE));
			}
		}
		
		private function handleEnterFrame(event : Event) : void
		{
			if(useFakeSmothness)
			{
				calculateCurrentPercentsPerFrame();
				_fakeProgressPercents += _currentPercentsPerFrame;
			}
			else
			{
				if(_progressPercents > _fakeProgressPercents)
				{
					_fakeProgressPercents = _progressPercents;
				}
			}
			
			onProgressUpdated();
		}
		
		private function calculateCurrentPercentsPerFrame() : void
		{
			if(_progressPercents > _fakeProgressPercents)
			{
				var difference : Number = _progressPercents - _fakeProgressPercents;
				
				if(difference >= sensitivePercentsDifference)
				{
					_currentPercentsPerFrame = maxPercentsPerFrame;				
				}
				else
				{
					var relation : Number = difference / sensitivePercentsDifference;
					_currentPercentsPerFrame = 
						normalPercentsPerFrame + ((maxPercentsPerFrame - normalPercentsPerFrame) * relation); 
				}
				
				if((progressPercents != 100) && 
					((100 - _fakeProgressPercents) < sensitivePercentsDifference) &&
					(_currentPercentsPerFrame > progressPercents - _fakeProgressPercents))
				{
					_currentPercentsPerFrame = progressPercents - _fakeProgressPercents;
				}
			}
			else
			{
				if(100 - _fakeProgressPercents < sensitivePercentsDifference)
				{
					_currentPercentsPerFrame = 0;
				}
				else
				{
					_currentPercentsPerFrame = minPercentsPerFrame;
				}
			}
		}
		
		private function handleProgressDispatcherProgress(event : ProgressEvent) : void
		{
			progressTo(event.bytesLoaded / event.bytesTotal * 100);
		}
	}
}